#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@desc: .

@Project ：kuberCloudTest 
@File ：utils.py
@Author ：admin
@Date ：2024/3/21 14:54 
"""
from kuberCloudTest.common.basic import basicUtils
from kuberCloudTest.exception import KuberCloudException


class vmUtils(basicUtils):

    def __init__(self, accessToken):
        super().__init__(accessToken)


class BasicConf:

    def __init__(self, name, number: int = 1, labelIds='', remark='',
                 agid='', clockOffset='utc', vmLevel: int = 1, consoleMode: int = 1, usbRedirect: bool = True,
                 start: bool = True, sshKey: str = '', userData: str = '', version='', encrypt: bool = False):
        """
        基础配置-初始化参数
        :param name: 名称
        :param number: 数量
        :param labelIds: 标签ID(多个使用英文逗号分割)
        :param remark: 简介
        :param agid: 亲合组ID
        :param clockOffset: 时钟模式（默认utc） 【utc|localtime】
        :param vmLevel: 高可用级别（默认 1） 【1: None; 2: NeverStop】
        :param consoleMode: 控制台模式（默认 1） 【1：vnc; 2：spice; 3：spice+vnc;】
        :param usbRedirect: USB重定向（默认 True） 【True|False】
        :param start: 是否启动（默认 True） 【True|False】
        :param sshKey: ssh-key
        :param userData: user-data
        :param version: 版本兼容
        :param encrypt: 是否加密（默认 False） 【True|False】
        """

        self.name = name
        self.number = number
        self.labelIds = labelIds
        self.remark = remark

        self.agid = agid
        self.clockOffset = clockOffset
        self.vmLevel = vmLevel
        self.consoleMode = consoleMode
        self.usbRedirect = usbRedirect
        self.start = start
        self.sshKey = sshKey
        self.userData = userData
        self.version = version
        self.encrypt = encrypt

        if self.clockOffset not in ['utc', 'localtime']:
            raise KuberCloudException('params error', 'clockOffset should be utc or localtime')
        if self.consoleMode not in [1, 2, 3]:
            raise KuberCloudException(
                'params error', 'consoleMode should be 1(vnc) or 2(spice) or 3(spice+vnc)')
        if self.vmLevel not in [1, 2]:
            raise KuberCloudException('params error', 'vmLevel should be 1(None) or 2(NeverStop)')


class ComputeResourceConf:

    def __init__(self, specId, mirrorId,
                 videoCount: int = 1,
                 videoModelType: str = 'virtio', videoModelVram: int = 16384, videoModelRam: int = 65536,
                 rootPreAllocation: str = 'off', rootDiskSpecId='',
                 dataPreAllocation: str = 'off', dataDiskSpecId: list = [],
                 isoid: list = [], gpuSpec='', vgpuSpec=''
                 ):
        """
        计算资源配置-初始化参数
        :param specId: 计算规格ID
        :param mirrorId: 系统镜像ID
        :param videoCount: video个数（默认1）
        :param videoModelType: video模式（默认virtio）【virtio|qxl|cirrus】
        :param videoModelVram:
        :param videoModelRam:
            备注：
                videoModelType=virtio时，videoModelVram和videoModelRam默认值均为0
                videoModelType=qxl时，  videoModelVram和videoModelRam默认值均为65536
                videoModelType=cirrus时，  videoModelVram默认值为65536，videoModelRam默认值为0

        :param rootDiskSpecId: 根云盘盘规格ID（当系统盘镜像为iso格式时，该参数必填）
        :param rootPreAllocation: 根云盘预分配策略（默认精简置备） 【off：精简置备；falloc：厚置备（延迟置零）；full：厚置备（置零）】
        :param dataDiskSpecId: 数据盘规格ID（数组格式）
        :param dataPreAllocation: 数据云盘预分配策略（默认精简置备） 【off：精简置备；falloc：厚置备（延迟置零）；full：厚置备（置零）】
        :param isoid: 虚拟光驱ID（数组格式，最多选择3个，且光驱必须是iso镜像格式）
        :param gpuSpec: gpu规格
        :param vgpuSpec: vgpu规格
        """
        self.specId = specId
        self.mirrorId = mirrorId

        self.videoCount = videoCount
        self.videoModelType = videoModelType
        self.videoModelVram = videoModelVram
        self.videoModelRam = videoModelRam
        self.rootPreAllocation = rootPreAllocation
        self.rootDiskSpecId = rootDiskSpecId
        self.dataPreAllocation = dataPreAllocation
        self.dataDiskSpecId = dataDiskSpecId
        self.isoid = isoid
        self.gpuSpec = gpuSpec
        self.vgpuSpec = vgpuSpec

        if self.dataPreAllocation not in ['off', 'falloc', 'full']:
            raise KuberCloudException(
                'params error', 'dataPreAllocation should be off or falloc or full')
        if self.rootPreAllocation not in ['off', 'falloc', 'full']:
            raise KuberCloudException(
                'params error', 'rootPreAllocation should be off or falloc or full')
        if self.videoModelType not in ['virtio', 'qxl', 'cirrus']:
            raise KuberCloudException(
                'params error', 'videoModelType should be virtio or qxl or cirrus')
        if self.videoModelType == 'virtio':
            self.videoModelVram = 0
            self.videoModelRam = 0
        if self.videoModelType == 'cirrus':
            self.videoModelRam = 0


class StorageResourceConf:

    def __init__(self, allocatorStrategy: int = 1, hostId='', msid='', dataMsid='', hugePage=''):
        """
        存储资源配置-初始化参数
        :param allocatorStrategy: 存储分配策略（默认 1） 【1: 系统分配（则后续根云盘主存储和数据盘主存储随机分配）; 2: 手动分配】
        :param hostId: 物理机ID（默认不填，则创建云主机随机分配，填写则云主机创建在指定物理机上）
        :param msid: 根云盘主存储ID（存储分配策略为2必须填写），对应主存储页面数据的UUID
        :param dataMsid: 数据盘主存储ID（存储分配策略为2，且数据盘规格有选值时必须填写），对应主存储页面数据的UUID
        :param hugePage: 内存大页（默认单位MB，如3MB，2GB）
        """
        self.allocatorStrategy = allocatorStrategy
        self.hostId = hostId
        self.msid = msid
        self.dataMsid = dataMsid
        self.hugePage = hugePage

        if self.allocatorStrategy not in [1, 2]:
            raise KuberCloudException(
                'params error', 'allocatorStrategy should be 1 or 2')

        self.hugePageUnit, self.hugePageValue, self.hugePageSize = self._get_hugePage()

    def _get_hugePage(self):
        hugePageUnit = ''
        hugePageValue = ''
        hugePageSize = ''
        if self.hugePage:
            unit = ''
            multiplier = 1
            hugePageUnit = 2
            if self.hugePage.endswith('MB'):
                unit = 'MB'
                hugePageUnit = 2
                multiplier = 1024
            elif self.hugePage.endswith('GB'):
                unit = 'GB'
                hugePageUnit = 1
                multiplier = 1024 * 1024
            if unit:
                hugePageValue = int(self.hugePage.split(unit)[0])
                hugePageSize = hugePageValue * multiplier

        return hugePageValue, hugePageUnit, hugePageSize


class NetworkResourceConf:

    def __init__(self, threeLayerNetworkIds: list):
        """
        计算资源配置-初始化参数
        :param threeLayerNetworkIds: 三层网络ID（此处不支持指定网络，系统自动分配）
        """
        self.threeLayerNetworkIds = threeLayerNetworkIds

        if not self.threeLayerNetworkIds:
            raise KuberCloudException('params error', 'threeLayerNetworkIds should not be empty')
        self.ips, self.ipv6s, self.networkIds = self._getNetworkStr()

    def _getNetworkStr(self):
        ips = ''
        ipv6s = ''
        networkIds = ''
        for networkId in self.threeLayerNetworkIds:
            ips = ips + str(networkId) + ':' + ','
            ipv6s = ipv6s + str(networkId) + '_' + ','
            networkIds = networkIds + str(networkId) + ','

        ips = ips if not ips.endswith(',') else ips[:-1]
        ipv6s = ipv6s if not ipv6s.endswith(',') else ipv6s[:-1]
        networkIds = networkIds if not networkIds.endswith(',') else networkIds[:-1]

        return ips, ipv6s, networkIds


def get_create_vm_params(basicConf: BasicConf,
                         computeResourceConf: ComputeResourceConf,
                         storageResourceConf: StorageResourceConf, networkResourceConf: NetworkResourceConf):
    data = dict()
    # 网络资源配置
    data['ips'] = networkResourceConf.ips
    data['ipv6s'] = networkResourceConf.ipv6s
    data['networkids'] = networkResourceConf.networkIds

    # 基础资源配置
    data['name'] = basicConf.name
    data['number '] = basicConf.number
    data['labelIds'] = basicConf.labelIds
    data['remark'] = basicConf.remark
    data['agid'] = basicConf.agid
    data['clockoffset'] = basicConf.clockOffset
    data['vmlevel'] = basicConf.vmLevel
    data['vmconsolemode'] = basicConf.consoleMode
    data['usbredirect'] = basicConf.usbRedirect
    data['encrypt'] = basicConf.encrypt
    data['start'] = basicConf.start
    data['sshkey'] = basicConf.sshKey
    data['userdata'] = basicConf.userData
    data['version'] = basicConf.version

    # 计算资源配置
    data['specid'] = computeResourceConf.specId
    data['mirrorid'] = computeResourceConf.mirrorId
    data['rootpreallocation'] = computeResourceConf.rootPreAllocation
    data['rootdiskspecid'] = computeResourceConf.rootDiskSpecId
    data['datadiskspecid'] = computeResourceConf.dataDiskSpecId
    data['datapreallocation'] = computeResourceConf.dataPreAllocation
    data['isoid'] = computeResourceConf.isoid
    data['gpuspec'] = computeResourceConf.gpuSpec
    data['vgpuspec'] = computeResourceConf.vgpuSpec
    data['videoCount'] = computeResourceConf.videoCount
    data['videomodeltype'] = computeResourceConf.videoModelType
    data['videomodelvram'] = computeResourceConf.videoModelVram
    data['videomodelram'] = computeResourceConf.videoModelRam

    # 存储资源配置
    if storageResourceConf.allocatorStrategy == 1:
        data['dataMsid'] = ''
        data['msid'] = ''
    else:
        if not storageResourceConf.msid:
            raise KuberCloudException(
                'params error', 'msid should not be empty when allocatorStrategy is 2')
        data['msid'] = storageResourceConf.msid
        if computeResourceConf.dataDiskSpecId:
            if not storageResourceConf.dataMsid:
                raise KuberCloudException(
                    'params error',
                    'dataMsid should not be empty when allocatorStrategy is 2 and dataDiskSpecId is not none')
            data['dataMsid'] = storageResourceConf.dataMsid
    data['hostid'] = storageResourceConf.hostId

    if storageResourceConf.hugePage and storageResourceConf.hugePageUnit \
            and storageResourceConf.hugePageValue and storageResourceConf.hugePageSize:
        data['hugePage'] = storageResourceConf.hugePage
        data['hugePageValue'] = storageResourceConf.hugePageValue
        data['hugePageUnit'] = storageResourceConf.hugePageUnit
        data['hugePageSize'] = storageResourceConf.hugePageSize

    return data
